package meiyunting.shiwuzhaoling.service;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Supplier;

/**
 * 简单的断路器实现，不依赖于Resilience4J
 */
@Component
public class SimpleCircuitBreaker {
    
    private static final Logger log = LoggerFactory.getLogger(SimpleCircuitBreaker.class);
    
    // 断路器状态
    private enum State {
        CLOSED,     // 关闭状态，允许请求通过
        OPEN,       // 开放状态，快速失败
        HALF_OPEN   // 半开状态，允许有限请求通过以测试服务是否恢复
    }
    
    // 断路器配置
    private static final int FAILURE_THRESHOLD = 5;         // 失败阈值
    private static final long RESET_TIMEOUT = 30000;        // 重置超时时间(毫秒)
    private static final int MAX_HALF_OPEN_REQUESTS = 3;    // 半开状态下允许的最大请求数
    
    // 服务断路器状态缓存
    private final Map<String, State> circuitState = new ConcurrentHashMap<>();
    private final Map<String, AtomicInteger> failureCount = new ConcurrentHashMap<>();
    private final Map<String, Long> lastFailureTime = new ConcurrentHashMap<>();
    private final Map<String, AtomicInteger> halfOpenRequestCount = new ConcurrentHashMap<>();
    
    /**
     * 执行带断路保护的操作
     * @param serviceId 服务ID
     * @param operation 要执行的操作
     * @param fallback 失败后的降级操作
     * @param <T> 返回类型
     * @return 操作结果或降级结果
     */
    public <T> T execute(String serviceId, Supplier<T> operation, Supplier<T> fallback) {
        // 初始化服务的断路器状态
        circuitState.putIfAbsent(serviceId, State.CLOSED);
        failureCount.putIfAbsent(serviceId, new AtomicInteger(0));
        lastFailureTime.putIfAbsent(serviceId, System.currentTimeMillis());
        halfOpenRequestCount.putIfAbsent(serviceId, new AtomicInteger(0));
        
        // 检查当前断路器状态
        State currentState = circuitState.get(serviceId);
        
        // 如果断路器开路，检查是否应该进入半开状态
        if (currentState == State.OPEN) {
            long now = System.currentTimeMillis();
            long lastFailure = lastFailureTime.get(serviceId);
            
            if (now - lastFailure > RESET_TIMEOUT) {
                log.info("Circuit for service {} transitioning from OPEN to HALF_OPEN", serviceId);
                circuitState.put(serviceId, State.HALF_OPEN);
                halfOpenRequestCount.get(serviceId).set(0);
                currentState = State.HALF_OPEN;
            } else {
                log.debug("Circuit for service {} is OPEN, fast failing", serviceId);
                return fallback.get();
            }
        }
        
        // 如果断路器半开，检查是否允许请求通过
        if (currentState == State.HALF_OPEN) {
            int currentRequests = halfOpenRequestCount.get(serviceId).incrementAndGet();
            if (currentRequests > MAX_HALF_OPEN_REQUESTS) {
                log.debug("Circuit for service {} is HALF_OPEN but request quota exceeded", serviceId);
                return fallback.get();
            }
        }
        
        // 尝试执行操作
        try {
            T result = operation.get();
            
            // 操作成功，重置故障计数
            if (currentState == State.HALF_OPEN) {
                log.info("Request succeeded in HALF_OPEN state, resetting circuit for service {}", serviceId);
                circuitState.put(serviceId, State.CLOSED);
            }
            
            failureCount.get(serviceId).set(0);
            return result;
        } catch (Exception e) {
            // 记录故障
            log.warn("Circuit breaker: operation failed for service {}: {}", serviceId, e.getMessage());
            lastFailureTime.put(serviceId, System.currentTimeMillis());
            
            // 更新失败计数和断路器状态
            int failures = failureCount.get(serviceId).incrementAndGet();
            if (failures >= FAILURE_THRESHOLD || currentState == State.HALF_OPEN) {
                log.info("Circuit for service {} transitioning to OPEN due to {} failures", serviceId, failures);
                circuitState.put(serviceId, State.OPEN);
            }
            
            // 返回降级结果
            return fallback.get();
        }
    }
} 